namespace Aphalina.Compression
{
    using System;
    using System.IO;
    using System.Runtime.CompilerServices;

    public class BitWriter
    {
        private byte[] buffer = new byte[0x1000];
        private int currentBits;
        private int freeBits = 8;
        private int position;

        public BitWriter(Stream stream)
        {
            this.BaseStream = stream;
        }

        public void AlignToByte()
        {
            if (this.freeBits != 8)
            {
                this.WriteBits(0, this.freeBits);
            }
        }

        public void Flush()
        {
            this.AlignToByte();
            if (this.position > 0)
            {
                this.BaseStream.Write(this.buffer, 0, this.position);
                this.position = 0;
            }
        }

        public void WriteBits(int bits, int len)
        {
            while (len > 0)
            {
                int freeBits = len;
                if (this.freeBits < len)
                {
                    freeBits = this.freeBits;
                }
                this.currentBits |= bits << (8 - this.freeBits);
                this.freeBits -= freeBits;
                if (this.freeBits == 0)
                {
                    this.buffer[this.position] = (byte) (this.currentBits & 0xff);
                    this.position++;
                    if (this.position == this.buffer.Length)
                    {
                        this.BaseStream.Write(this.buffer, 0, this.buffer.Length);
                        this.position = 0;
                    }
                    this.freeBits = 8;
                    this.currentBits = 0;
                }
                bits = bits >> freeBits;
                len -= freeBits;
            }
        }

        public Stream BaseStream { get; private set; }
    }
}

